﻿using DevExpress.Utils.DirectXPaint;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace Marmat.Template.WinForm
{
    /// <summary>
    /// 对象变化跟踪工厂
    /// </summary>
    public class ObjectConversionFactory
    {
        private static Dictionary<object, object> ObjectCollection
        {
            get
            {
                if (_objectCollection is null)
                    _objectCollection = new Dictionary<object, object>();
                return _objectCollection;
            }
        }
        private static Dictionary<object, object> _objectCollection = new Dictionary<object, object>();

        /// <summary>
        /// 存储对象副本
        /// </summary>
        /// <param name="instance"></param>
        public static void StorageObject(object instance)
        {
            if (instance is null)
                return;

            //拷贝对象，如果对象实现了SerializableAttribute特性，则使用二进制流拷贝对象，否则使用json序列化对象副本。
            var serializable = instance.GetType().GetCustomAttribute<SerializableAttribute>();
            if (serializable is not null)
            {
                BinaryFormatter bf = new BinaryFormatter();
                using MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, instance);//将对象序列化到内存中
                ms.Position = default;//将内存流的位置设为0
                object value = bf.Deserialize(ms);//继续反序列化
                ObjectCollection[instance] = value;
            }
            else
            {
                var str = Newtonsoft.Json.JsonConvert.SerializeObject(instance);
                object value = Newtonsoft.Json.JsonConvert.DeserializeObject(str, instance.GetType());
                ObjectCollection[instance] = value;
            }
        }

        /// <summary>
        /// 判断是否包含指定主键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool ContainsKey(object key)
        {
            return ObjectCollection.ContainsKey(key);
        }

        /// <summary>
        /// 判断是否包含指定主键
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool ContainsKey<T>(T key)
        {
            return ObjectCollection.ContainsKey(key);
        }
        /// <summary>
        /// 获取对象的副本文件
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static object GetObject(object instance)
        {
            return ObjectCollection[instance];
        }

        /// <summary>
        /// 获取对象的副本文件
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static T GetObject<T>(T instance) where T : class
        {
            return ObjectCollection[instance] as T;
        }

        /// <summary>
        /// 移除副本文件
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static bool RemoveObject(object instance)
        {
            return ObjectCollection.Remove(instance);
        }

        /// <summary>
        /// 获取对象转换实例。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static ObjectConversion GetConversion<T>()
        {
            IObjectConversionProvider factory = Marmat.FrameWork.SystemCommand.GetService<IObjectConversionProvider>();
            return factory.GetConversion<T>();
        }

        /// <summary>
        /// 获取对象变更的清单
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="current"></param>
        /// <returns></returns>
        public static Dictionary<string, object> Conversion<T>(T current) where T : class
        {
            var source = GetObject(current);
            return Conversion<T>(source, current);
        }

        /// <summary>
        /// 获取对象变更属性的字典。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="current"></param>
        /// <param name="conversion"></param>
        /// <returns>返回一个字典，该字典里面包含了变更的属性列表。</returns>
        public static Dictionary<string, object> Conversion<T>(T current, ObjectConversion conversion) where T : class
        {
            var source = GetObject(current);
            return Conversion(source, current, conversion);
        }

        /// <summary>
        /// 获取对象变更属性的字典。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="current"></param>
        /// <param name="conversion"></param>
        /// <returns></returns>
        public static Dictionary<string, object> Conversion<T>(T source, T current, ObjectConversion conversion = null) where T : class
        {
            if (conversion is null)
                conversion = GetConversion<T>();
            return conversion.Conversion(source, current);
        }

        /// <summary>
        /// 获取对象是否被更改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="current"></param>
        /// <returns></returns>
        public static bool HasChanges<T>(T current) where T : class
        {
            ObjectConversion conversion = ObjectConversionFactory.GetConversion<T>();
            return HasChanges(current, conversion);
        }

        /// <summary>
        /// 获取对象是否被更改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="current"></param>
        /// <param name="conversion"></param>
        /// <returns></returns>
        public static bool HasChanges<T>(T current, ObjectConversion conversion) where T : class
        {
            var source = GetObject(current);
            return conversion.HasChanges(source, current);
        }
    }
}
